package edu.mit.nice.struct;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.Socket;
import java.util.HashSet;

import edu.mit.nice.NiceClient;
import edu.mit.nice.NiceState;
import edu.mit.nice.message.JoinLayerMessage;
import edu.mit.nice.message.JoinLayerReplyMessage;
import edu.mit.nice.message.Message;

public class Node implements Serializable
{	
	private transient Socket socket = null;
	private transient SocketHandler handler = null;
	private transient NiceClient client = null;
	private transient NiceState state = null;

	private InetAddress address;
	private int port;
	
	public Node(InetAddress address, int port)
	{
		this.address = address;
		this.port = port;
	}

	public void recreate(NiceClient client) throws IOException
	{
		this.client = client;
		socket = new Socket(address, port);
		
		handler = new SocketHandler(this);
		handler.start();
	}

	public Socket getSocket()
	{
		return socket;
	}
	
	public void sendMessage(Message message) throws IOException, ClassNotFoundException
	{
		ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
		
		oos.writeObject(message);
	}
	
	private void handleMessage(Message reply) throws IOException, ClassNotFoundException
	{	
		System.out.println("Got: " + reply);
		
		if(reply instanceof JoinLayerReplyMessage)
		{	

			JoinLayerReplyMessage jlrm = (JoinLayerReplyMessage)reply;
			
			Cluster c = jlrm.getCluster();
			
			if(jlrm.getYourLayer() == c.getLayer())
			{
				client.attach(c.getLeader(), jlrm.getYourLayer());
			}
			else
			{
				HashSet<Node> nodes = c.getNodes();
				
				for(Node n: nodes)
				{
					n.sendMessage(new JoinLayerMessage(jlrm.getYourLayer()));
				}
			}
		}
	}
	
	private class SocketHandler extends Thread
	{
		private Node thisnode;
		
		public SocketHandler(Node thisnode) {
			this.thisnode = thisnode;
		}

		public void run()
		{
			ObjectInputStream ois;
			try {
				ois = new ObjectInputStream(thisnode.socket.getInputStream());
				
				Message reply = (Message)ois.readObject();
				
				thisnode.handleMessage(reply);
				
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}